﻿/*----------------------------------------------------------------
//  <copyright file="FunctionAuthorizationManagerBase.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-01-31 13:55</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.Authorization
{
    #region "功能权限管理器基类"
    /// <summary>
    /// 功能权限管理器基类
    /// </summary>
    /// <typeparam name="TFunction">功能类型</typeparam>
    /// <typeparam name="TFunctionInputDto">功能输入DTO类型</typeparam>
    /// <typeparam name="TModule">模块类型</typeparam>
    /// <typeparam name="TModuleInputDto">模块输入类型</typeparam>
    /// <typeparam name="TModuleKey">模块编号类型</typeparam>
    /// <typeparam name="TModuleFunction">模块功能类型</typeparam>
    /// <typeparam name="TModuleRole">模块角色类型</typeparam>
    /// <typeparam name="TModuleUser">模块用户类型</typeparam>
    /// <typeparam name="TUserRole">用户角色类型</typeparam>
    /// <typeparam name="TUserRoleKey">用户角色编号类型</typeparam>
    /// <typeparam name="TRole">角色类型</typeparam>
    /// <typeparam name="TRoleKey">角色编号类型</typeparam>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <typeparam name="TUserKey">用户编号类型</typeparam>
    public abstract class FunctionAuthorizationManagerBase<TFunction, TFunctionInputDto, TModule, TModuleInputDto, TModuleKey,
            TModuleFunction, TModuleRole, TModuleUser, TUserRole, TUserRoleKey, TRole, TRoleKey, TUser, TUserKey>
        : IFunctionStore<TFunction, TFunctionInputDto>,
          IModuleStore<TModule, TModuleInputDto, TModuleKey>,
          IModuleFunctionStore<TModuleFunction, TModuleKey>,
          IModuleRoleStore<TModuleRole, TRoleKey, TModuleKey>,
          IModuleUserStore<TModuleUser, TUserKey, TModuleKey>
        where TFunction : IFunction
        where TFunctionInputDto : FunctionInputDtoBase
        where TModule : ModuleBase<TModuleKey>
        where TModuleInputDto : ModuleInputDtoBase<TModuleKey>
        where TModuleFunction : ModuleFunctionBase<TModuleKey>, new()
        where TModuleRole : ModuleRoleBase<TModuleKey, TRoleKey>, new()
        where TModuleUser : ModuleUserBase<TModuleKey, TUserKey>, new()
        where TModuleKey : struct, IEquatable<TModuleKey>
        where TUserRole : UserRoleBase<TUserRoleKey, TUserKey, TRoleKey>
        where TUserRoleKey : struct, IEquatable<TUserRoleKey>
        where TRole : RoleBase<TRoleKey, TUserKey>
        where TUser : UserBase<TUserKey>
        where TRoleKey : struct, IEquatable<TRoleKey>
        where TUserKey : struct, IEquatable<TUserKey>
    {
        //字段
        private readonly IServiceProvider _provider;

        #region "属性"
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus => _provider.GetService<IEventBus>();
        #endregion
        #region "获取 功能仓储"
        /// <summary>
        /// 获取 功能仓储
        /// </summary>
        protected IRepository<TFunction, long> FunctionRepository => _provider.GetService<IRepository<TFunction, long>>();
        #endregion
        #region "获取 模块仓储"
        /// <summary>
        /// 获取 模块仓储
        /// </summary>
        protected IRepository<TModule, TModuleKey> ModuleRepository => _provider.GetService<IRepository<TModule, TModuleKey>>();
        #endregion
        #region "获取 模块功能仓储"
        /// <summary>
        /// 获取 模块功能仓储
        /// </summary>
        protected IRepository<TModuleFunction, long> ModuleFunctionRepository => _provider.GetService<IRepository<TModuleFunction, long>>();
        #endregion
        #region "获取 模块角色仓储"
        /// <summary>
        /// 获取 模块角色仓储
        /// </summary>
        protected IRepository<TModuleRole, long> ModuleRoleRepository => _provider.GetService<IRepository<TModuleRole, long>>();
        #endregion
        #region "获取 模块用户仓储"
        /// <summary>
        /// 获取 模块用户仓储
        /// </summary>
        protected IRepository<TModuleUser, long> ModuleUserRepository => _provider.GetService<IRepository<TModuleUser, long>>();
        #endregion
        #region "获取 用户角色仓储"
        /// <summary>
        /// 获取 用户角色仓储
        /// </summary>
        protected IRepository<TUserRole, TUserRoleKey> UserRoleRepository => _provider.GetService<IRepository<TUserRole, TUserRoleKey>>();
        #endregion
        #region "获取 角色仓储"
        /// <summary>
        /// 获取 角色仓储
        /// </summary>
        protected IRepository<TRole, TRoleKey> RoleRepository => _provider.GetService<IRepository<TRole, TRoleKey>>();
        #endregion
        #region "获取 用户仓储"
        /// <summary>
        /// 获取 用户仓储
        /// </summary>
        protected IRepository<TUser, TUserKey> UserRepository => _provider.GetService<IRepository<TUser, TUserKey>>();
        #endregion

        #endregion

        #region "属性 - Implementation of IFunctionStore<TFunction,in TFunctionInputDto>"
        #region "获取 功能信息查询数据集"
        /// <summary>
        /// 获取 功能信息查询数据集
        /// </summary>
        public IQueryable<TFunction> Functions => FunctionRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "属性 - Implementation of IModuleStore<TModule,in TModuleInputDto,in TModuleKey>"
        #region "获取 模块信息查询数据集"
        /// <summary>
        /// 获取 模块信息查询数据集
        /// </summary>
        public IQueryable<TModule> Modules => ModuleRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "属性 - Implementation of IModuleFunctionStore<TModuleFunction>"
        #region "获取 模块功能信息查询数据集"
        /// <summary>
        /// 获取 模块功能信息查询数据集
        /// </summary>
        public IQueryable<TModuleFunction> ModuleFunctions => ModuleFunctionRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "属性 - Implementation of IModuleRoleStore<TModuleRole>"
        #region "获取 模块角色信息查询数据集"
        /// <summary>
        /// 获取 模块角色信息查询数据集
        /// </summary>
        public IQueryable<TModuleRole> ModuleRoles => ModuleRoleRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "属性 - Implementation of IModuleUserStore<TModuleUser>"
        #region "获取 模块用户信息查询数据集"
        /// <summary>
        /// 获取 模块用户信息查询数据集
        /// </summary>
        public IQueryable<TModuleUser> ModuleUsers => ModuleUserRepository.QueryAsNoTracking();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个功能权限管理器基类的新实例"
        /// <summary>
        /// 初始化一个功能权限管理器基类 <see cref="FunctionAuthorizationManagerBase{TFunction, TFunctionInputDto, TModule, TModuleInputDto, TModuleKey,TModuleFunction, TModuleRole, TModuleUser, TUserRole, TUserRoleKey, TRole, TRoleKey, TUser, TUserKey}"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        protected FunctionAuthorizationManagerBase(IServiceProvider provider)
        {
            _provider = provider;
        }
        #endregion

        #endregion

        #region "方法 - Implementation of IFunctionStore<TFunction,in TFunctionInputDto>"
        #region "检查功能信息是否存在"
        /// <summary>
        /// 检查功能信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">更新的功能信息编号</param>
        /// <returns>功能信息是否存在</returns>
        public virtual async Task<bool> CheckFunctionExists(Expression<Func<TFunction, bool>> predicate, long id = default)
        {
            return await FunctionRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "更新功能信息"
        /// <summary>
        /// 更新功能信息
        /// </summary>
        /// <param name="dtos">包含更新信息的功能信息DTO信息</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> UpdateFunctions(params TFunctionInputDto[] dtos)
        {
            Check.Validate<TFunctionInputDto, long>(dtos, nameof(dtos));

            OperationResult result = await FunctionRepository.UpdateAsync(dtos,
               (dto, entity) =>
               {
                   if (dto.IsLocked && entity.Area == "Admin" && entity.Controller == "Function" && (entity.Action == "Update" || entity.Action == "Read"))
                   {
                       throw new Exception(I18N.T("功能 {0} 不能锁定", entity.Name));
                   }
                   if (dto.AuditEntityEnabled && !dto.AuditOperationEnabled && !entity.AuditOperationEnabled && !entity.AuditEntityEnabled)
                   {
                       dto.AuditOperationEnabled = true;
                   }
                   else if (!dto.AuditOperationEnabled && dto.AuditEntityEnabled && entity.AuditOperationEnabled && entity.AuditEntityEnabled)
                   {
                       dto.AuditEntityEnabled = false;
                   }
                   if (dto.AccessType != entity.AccessType)
                   {
                       entity.IsAccessTypeChanged = true;
                   }
                   return Task.FromResult(0);
               });

            if (result.Succeeded)
            {
                //功能信息缓存刷新事件
                await EventBus?.PublishAsync(new FunctionCacheRefreshEventData());

                //功能权限缓存刷新事件
                FunctionAuthCacheRefreshEventData eventData = new()
                {
                    FunctionIds = dtos.Select(m => m.Id).ToArray()
                };
                await EventBus?.PublishAsync(eventData);
            }
            return result;
        }
        #endregion

        #endregion

        #region "方法 - Implementation of IModuleStore<TModule,in TModuleInputDto,in TModuleKey>"
        #region "检查模块信息是否存在"
        /// <summary>
        /// 检查模块信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">更新的模块信息编号</param>
        /// <returns>模块信息是否存在</returns>
        public virtual async Task<bool> CheckModuleExists(Expression<Func<TModule, bool>> predicate, TModuleKey id = default(TModuleKey))
        {
            return await ModuleRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "添加模块信息"
        /// <summary>
        /// 添加模块信息
        /// </summary>
        /// <param name="dto">要添加的模块信息DTO信息</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> CreateModule(TModuleInputDto dto)
        {
            Check.NotNull(dto, nameof(dto));
            if (dto.Name.Contains('.'))
            {
                return OperationResult.Error(I18N.T("模块 {0} 不能包含字符 '-'", dto.Name));
            }
            var exist = Modules.Where(m => m.Name == dto.Name && m.ParentId != null && m.ParentId.Equals(dto.ParentId))
                .SelectMany(m => Modules.Where(n => n.Id.Equals(m.ParentId)).Select(n => n.Name)).FirstOrDefault();
            if (exist != null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 中已存在名称为 {1} 的子模块", exist, dto.Name));
            }
            exist = Modules.Where(m => m.Code == dto.Code && m.ParentId != null && m.ParentId.Equals(dto.ParentId))
            .SelectMany(m => Modules.Where(n => n.Id.Equals(m.ParentId)).Select(n => n.Name)).FirstOrDefault();
            if (exist != null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 中已存在代码为 {1} 的子模块", exist, dto.Code));
            }

            TModule entity = dto.MapTo<TModuleInputDto, TModule>();
            //排序编号，不存在为1，否则同级最大+1
            var peerModules = Modules.Where(m => m.ParentId.Equals(dto.ParentId)).Select(m => new { m.OrderNo }).ToArray();
            if (peerModules.Length == 0)
            {
                entity.OrderNo = 1;
            }
            else
            {
                decimal maxCode = peerModules.Max(m => m.OrderNo);
                entity.OrderNo = maxCode + 1;
            }
            //父模块
            string parentTreePathString = null;
            if (!Equals(dto.ParentId, default(TModuleKey)))
            {
                var parent = Modules.Where(m => m.Id.Equals(dto.ParentId)).Select(m => new { m.Id, m.TreePathString }).FirstOrDefault();
                if (parent == null)
                {
                    return OperationResult.Error(I18N.T("模块 {0} 不存在", dto.ParentId));
                }
                entity.ParentId = dto.ParentId;
                parentTreePathString = parent.TreePathString;
            }
            else
            {
                entity.ParentId = null;
            }
            var result = await ModuleRepository.InsertAsync(entity);
            if (result.Succeeded)
            {
                entity.TreePathString = entity.ParentId == null
                    ? TreeHelper.FormatTreePathString(entity.Id)
                    : TreeHelper.GetTreePathString(entity.Id, parentTreePathString);
                var result1 = await ModuleRepository.UpdateAsync(entity);
                if (!result1.Succeeded)
                {
                    return result1;
                }

                return OperationResult.Success(I18N.T("模块 {0} 创建成功", dto.Name));
            }

            return result;
        }
        #endregion
        #region "更新模块信息"
        /// <summary>
        /// 更新模块信息
        /// </summary>
        /// <param name="dto">包含更新信息的模块信息DTO信息</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> UpdateModule(TModuleInputDto dto)
        {
            Check.NotNull(dto, nameof(dto));
            if (dto.Name.Contains('.'))
            {
                return OperationResult.Error(I18N.T("模块 {0} 不能包含字符 '-'", dto.Name));
            }
            var exist1 = Modules.Where(m => m.Name == dto.Name && m.ParentId != null && m.ParentId.Equals(dto.ParentId) && !m.Id.Equals(dto.Id))
                .SelectMany(m => Modules.Where(n => n.Id.Equals(m.ParentId)).Select(n => new { n.Id, n.Name })).FirstOrDefault();
            if (exist1 != null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 中已存在名称为 {1} 的子模块", exist1.Name, dto.Name));
            }
            var exist2 = Modules.Where(m => m.Code == dto.Code && m.ParentId != null && m.ParentId.Equals(dto.ParentId) && !m.Id.Equals(dto.Id))
                .SelectMany(m => Modules.Where(n => n.Id.Equals(m.ParentId)).Select(n => new { n.Id, n.Name })).FirstOrDefault();
            if (exist2 != null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 中已存在代码为 {1} 的子模块", exist2.Name, dto.Code));
            }
            TModule entity = await ModuleRepository.GetAsync(dto.Id);
            if (entity == null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 不存在", dto.Id));
            }
            entity = dto.MapTo(entity);
            if (!Equals(dto.ParentId, default(TModuleKey)))
            {
                if (!entity.ParentId.Equals(dto.ParentId))
                {
                    var parent = Modules.Where(m => m.Id.Equals(dto.ParentId)).Select(m => new { m.Id, m.TreePathString }).FirstOrDefault();
                    if (parent == null)
                    {
                        return OperationResult.Error(I18N.T("模块 {0} 不存在", dto.ParentId));
                    }
                    entity.ParentId = dto.ParentId;
                    entity.TreePathString = TreeHelper.GetTreePathString(entity.Id, parent.TreePathString);
                }
            }
            else
            {
                entity.ParentId = null;
                entity.TreePathString = TreeHelper.FormatTreePathString(entity.Id);
            }
            var result = await ModuleRepository.UpdateAsync(entity);
            if (result.Succeeded)
            {
                return OperationResult.Success(I18N.T("模块 {0} 更新成功", dto.Name));
            }
            return result;
        }
        #endregion
        #region "删除模块信息"
        /// <summary>
        /// 删除模块信息
        /// </summary>
        /// <param name="id">要删除的模块信息编号</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> DeleteModule(TModuleKey id)
        {
            TModule entity = await ModuleRepository.GetAsync(id);
            if (entity != null)
            {
                if (await ModuleRepository.CheckExistsAsync(m => m.ParentId.Equals(id)))
                {
                    return OperationResult.Error(I18N.T("模块 {0} 存在子模块", entity.Name));
                }
                //清除附属引用
                await ModuleFunctionRepository.DeleteBatchAsync(m => m.ModuleId.Equals(id));
                await ModuleRoleRepository.DeleteBatchAsync(m => m.ModuleId.Equals(id));
                await ModuleUserRepository.DeleteBatchAsync(m => m.ModuleId.Equals(id));

                var result = await ModuleRepository.DeleteAsync(entity);
                if (result.Succeeded)
                {
                    //功能权限缓存刷新事件
                    var functionIds = ModuleFunctionRepository.QueryAsNoTracking(m => m.ModuleId.Equals(id)).Select(m => m.FunctionId).ToArray();
                    FunctionAuthCacheRefreshEventData eventData = new() { FunctionIds = functionIds };
                    await EventBus?.PublishAsync(eventData);

                    return OperationResult.Success(I18N.T("模块 {0} 删除成功", entity.Name));
                }
                return result;
            }

            return OperationResult.Success();
        }
        #endregion
        #region "获取树节点及其子节点的所有模块编号"
        /// <summary>
        /// 获取树节点及其子节点的所有模块编号
        /// </summary>
        /// <param name="rootIds">树节点</param>
        /// <returns>模块编号集合</returns>
        public virtual TModuleKey[] GetModuleTreeIds(params TModuleKey[] rootIds)
        {
            return rootIds.SelectMany(m => ModuleRepository.QueryAsNoTracking(n => n.TreePathString.Contains($"${m}$")).Select(n => n.Id)).Distinct()
                .ToArray();
        }
        #endregion

        #endregion

        #region "方法 - Implementation of IModuleFunctionStore<TModuleFunction>"
        #region "检查模块功能信息是否存在"
        /// <summary>
        /// 检查模块功能信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">更新的模块功能信息编号</param>
        /// <returns>模块功能信息是否存在</returns>
        public virtual async Task<bool> CheckModuleFunctionExists(Expression<Func<TModuleFunction, bool>> predicate, long id = default)
        {
            return await ModuleFunctionRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "设置模块的功能信息"
        /// <summary>
        /// 设置模块的功能信息
        /// </summary>
        /// <param name="moduleId">模块编号</param>
        /// <param name="functionIds">要设置的功能编号</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> SetModuleFunctions(TModuleKey moduleId, long[] functionIds)
        {
            TModule module = await ModuleRepository.GetAsync(moduleId);
            if (module == null)
            {
                return OperationResult.Error(I18N.T("模块 {0} 不存在", moduleId));
            }

            var existFunctionIds = ModuleFunctionRepository.QueryAsNoTracking(m => m.ModuleId.Equals(moduleId)).Select(m => m.FunctionId).ToArray();
            var addFunctionIds = functionIds.Except(existFunctionIds).ToArray();
            var removeFunctionIds = existFunctionIds.Except(functionIds).ToArray();
            List<string> addNames = new(), removeNames = new();
            int count = 0;
            foreach (var functionId in addFunctionIds)
            {
                TFunction function = await FunctionRepository.GetAsync(functionId);
                if (function == null)
                {
                    continue;
                }
                TModuleFunction moduleFunction = new() { ModuleId = moduleId, FunctionId = functionId };
                var result = await ModuleFunctionRepository.InsertAsync(moduleFunction);
                if (result.Succeeded)
                {
                    count += 1;
                    addNames.Add(function.Name);
                }
            }
            foreach (var functionId in removeFunctionIds)
            {
                TFunction function = await FunctionRepository.GetAsync(functionId);
                if (function == null)
                {
                    continue;
                }
                TModuleFunction moduleFunction = ModuleFunctionRepository.QueryAsNoTracking()
                    .FirstOrDefault(m => m.ModuleId.Equals(moduleId) && m.FunctionId == functionId);
                if (moduleFunction == null)
                {
                    continue;
                }
                var result = await ModuleFunctionRepository.DeleteAsync(moduleFunction);
                if (result.Succeeded)
                {
                    count += 1;
                    removeNames.Add(function.Name);
                }
            }

            if (count > 0)
            {
                //功能权限缓存刷新事件
                FunctionAuthCacheRefreshEventData eventData = new()
                {
                    FunctionIds = addFunctionIds.Union(removeFunctionIds).Distinct().ToArray()
                };
                await EventBus?.PublishAsync(eventData);
            }

            return OperationResult.Success(I18N.T("模块 {0} 添加功能 {1} 、移除功能 {2} 成功。", module.Name, addNames.ExpandAndToString(), removeNames.ExpandAndToString()));
        }
        #endregion

        #endregion

        #region "方法 - Implementation of IModuleRoleStore<TModuleRole>"
        #region "检查模块角色信息是否存在"
        /// <summary>
        /// 检查模块角色信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">更新的模块角色信息编号</param>
        /// <returns>模块角色信息是否存在</returns>
        public virtual async Task<bool> CheckModuleRoleExists(Expression<Func<TModuleRole, bool>> predicate, long id = default)
        {
            return await ModuleRoleRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "设置角色的可访问模块"
        /// <summary>
        /// 设置角色的可访问模块
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <param name="moduleIds">要赋予的模块编号集合</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> SetRoleModules(TRoleKey roleId, TModuleKey[] moduleIds)
        {
            TRole role = await RoleRepository.GetAsync(roleId);
            if (role == null)
            {
                return OperationResult.Error(I18N.T("角色 {0} 不存在", roleId));
            }

            TModuleKey[] existModuleIds = ModuleRoleRepository.QueryAsNoTracking(m => m.RoleId.Equals(roleId)).Select(m => m.ModuleId).ToArray();
            TModuleKey[] addModuleIds = moduleIds.Except(existModuleIds).ToArray();
            TModuleKey[] removeModuleIds = existModuleIds.Except(moduleIds).ToArray();
            int count = 0;

            foreach (TModuleKey moduleId in removeModuleIds)
            {
                TModuleRole moduleRole = ModuleRoleRepository.GetFirst(m => m.RoleId.Equals(roleId) && m.ModuleId.Equals(moduleId));
                if (moduleRole == null)
                {
                    continue;
                }
                var result = await ModuleRoleRepository.DeleteAsync(moduleRole);
                if (result.Succeeded)
                {
                    count += 1;
                }
            }
            foreach (TModuleKey moduleId in addModuleIds)
            {
                TModule module = await ModuleRepository.GetAsync(moduleId);
                if (module == null)
                {
                    return OperationResult.Error(I18N.T("模块 {0} 不存在", moduleId));
                }
                TModuleRole moduleRole = new() { ModuleId = moduleId, RoleId = roleId };
                var result = await ModuleRoleRepository.InsertAsync(moduleRole);
                if (result.Succeeded)
                {
                    count += 1;
                }
            }

            if (count > 0)
            {
                //功能权限缓存刷新事件
                moduleIds = addModuleIds.Union(removeModuleIds).Distinct().ToArray();
                var functionIds = ModuleFunctionRepository.QueryAsNoTracking(m => moduleIds.Contains(m.ModuleId)).Select(m => m.FunctionId).Distinct().ToArray();
                FunctionAuthCacheRefreshEventData eventData = new() { FunctionIds = functionIds };
                await EventBus?.PublishAsync(eventData);
            }

            if (addModuleIds.Length > 0 && removeModuleIds.Length == 0)
            {
                return OperationResult.Success(I18N.T("角色 {0} 添加模块 {1} 成功", role.Name, addModuleIds.ExpandAndToString()));
            }
            if (addModuleIds.Length == 0 && removeModuleIds.Length > 0)
            {
                return OperationResult.Success(I18N.T("角色 {0} 移除模块 {1} 成功", role.Name, removeModuleIds.ExpandAndToString()));
            }
            return OperationResult.Success(I18N.T("角色 {0} 添加模块 {1} 、移除模块 {2} 成功。", role.Name, addModuleIds.ExpandAndToString(), removeModuleIds.ExpandAndToString()));
        }
        #endregion
        #region "获取角色可访问模块编号"
        /// <summary>
        /// 获取角色可访问模块编号
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <returns>模块编号集合</returns>
        public virtual TModuleKey[] GetRoleModuleIds(TRoleKey roleId)
        {
            TModuleKey[] moduleIds = ModuleRoleRepository.QueryAsNoTracking(m => m.RoleId.Equals(roleId)).Select(m => m.ModuleId).Distinct().ToArray();
            return GetModuleTreeIds(moduleIds);
        }
        #endregion

        #endregion

        #region "方法 - Implementation of IModuleUserStore<TModuleUser>"
        #region "检查模块用户信息是否存在"
        /// <summary>
        /// 检查模块用户信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">更新的模块用户信息编号</param>
        /// <returns>模块用户信息是否存在</returns>
        public virtual async Task<bool> CheckModuleUserExists(Expression<Func<TModuleUser, bool>> predicate, long id = default)
        {
            return await ModuleUserRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "设置用户的可访问模块"
        /// <summary>
        /// 设置用户的可访问模块
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <param name="moduleIds">要赋给用户的模块编号集合</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> SetUserModules(TUserKey userId, TModuleKey[] moduleIds)
        {
            TUser user = await UserRepository.GetAsync(userId);
            if (user == null)
            {
                return OperationResult.Error(I18N.T("用户 {0} 不存在", userId));
            }

            TModuleKey[] existModuleIds = ModuleUserRepository.QueryAsNoTracking(m => m.UserId.Equals(userId)).Select(m => m.ModuleId).ToArray();
            TModuleKey[] addModuleIds = moduleIds.Except(existModuleIds).ToArray();
            TModuleKey[] removeModuleIds = existModuleIds.Except(moduleIds).ToArray();
            int count = 0;

            foreach (TModuleKey moduleId in removeModuleIds)
            {
                TModuleUser moduleUser = ModuleUserRepository.GetFirst(m => m.ModuleId.Equals(moduleId) && m.UserId.Equals(userId));
                if (moduleUser == null)
                {
                    continue;
                }
                var result = await ModuleUserRepository.DeleteAsync(moduleUser);
                if (result.Succeeded)
                {
                    count += 1;
                }
            }
            foreach (TModuleKey moduleId in addModuleIds)
            {
                TModule module = await ModuleRepository.GetAsync(moduleId);
                if (module == null)
                {
                    return OperationResult.Error(I18N.T("模块 {0} 不存在", moduleId));
                }
                TModuleUser moduleUser = new() { ModuleId = moduleId, UserId = userId };
                var result = await ModuleUserRepository.InsertAsync(moduleUser);
                if (result.Succeeded)
                {
                    count += 1;
                }
            }

            if (count > 0)
            {
                //功能权限缓存刷新事件
                FunctionAuthCacheRefreshEventData eventData = new() { UserIds = new[] { user.Id.ToString() } };
                await EventBus?.PublishAsync(eventData);
            }

            if (addModuleIds.Length > 0 && removeModuleIds.Length == 0)
            {
                return OperationResult.Success(I18N.T("用户 {0} 添加模块 {1} 成功", user.UserName, addModuleIds.ExpandAndToString()));
            }
            if (addModuleIds.Length == 0 && removeModuleIds.Length > 0)
            {
                return OperationResult.Success(I18N.T("用户 {0} 移除模块 {1} 成功", user.UserName, removeModuleIds.ExpandAndToString()));
            }
            return OperationResult.Success(I18N.T("用户 {0} 添加模块 {1} 、移除模块 {2} 成功。", user.UserName, addModuleIds.ExpandAndToString(), removeModuleIds.ExpandAndToString()));
        }
        #endregion
        #region "获取用户自己的可访问模块编号"
        /// <summary>
        /// 获取用户自己的可访问模块编号
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <returns>模块编号集合</returns>
        public virtual TModuleKey[] GetUserSelfModuleIds(TUserKey userId)
        {
            TModuleKey[] moduleIds = ModuleUserRepository.QueryAsNoTracking(m => m.UserId.Equals(userId)).Select(m => m.ModuleId).Distinct().ToArray();
            return GetModuleTreeIds(moduleIds);
        }
        #endregion
        #region "获取用户及其拥有角色可访问模块编号"
        /// <summary>
        /// 获取用户及其拥有角色可访问模块编号
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <returns>模块编号集合</returns>
        public virtual TModuleKey[] GetUserWithRoleModuleIds(TUserKey userId)
        {
            TModuleKey[] selfModuleIds = GetUserSelfModuleIds(userId);

            TRoleKey[] roleIds = UserRoleRepository.QueryAsNoTracking(m => m.UserId.Equals(userId)).Select(m => m.RoleId).ToArray();
            TModuleKey[] roleModuleIds = roleIds
                .SelectMany(m => ModuleRoleRepository.QueryAsNoTracking(n => n.RoleId.Equals(m)).Select(n => n.ModuleId))
                .Distinct().ToArray();
            roleModuleIds = GetModuleTreeIds(roleModuleIds);

            return roleModuleIds.Union(selfModuleIds).Distinct().ToArray();
        }
        #endregion

        #endregion

    }
    #endregion

}
